﻿/*
JEditableModule is a liteGrid plug-in that adds click-to-edit functionality using
the jEditable plug-in.

Author: MBH
DateAuthored: 7/11/09  
*/

function JEditableModule() {

	//Key codes.
	var enterKey = 13;

	var base = this;

    // function to check if a particular tdElement is editable
	var isEditableCallback;

	//Registers for events.
	base.initialize = function(liteGrid, options) {
		base.liteGrid = liteGrid;
		base.options = options;
		isEditableCallback = (options.isEditableCallback) || function() { return true; };

		//If jEditable isn't defined, we can't do anything.
		if (!$.editable) {
			console.log("Unable to initialize, can't find the jEditable plug-in.");
			return;
		}

		liteGrid.$el.bind("columnBound", base.columnBound);

		//This is used to track when we find a column with no configured editor.  We
		//only want to log the error once, not for every row that's bound.
		base.missingEditors = {};
	}

	//Attaches jEditable to editable columns.
	base.columnBound = function(event) {
		var column = event.column;
		var tdElement = event.element;
		var dataItem = event.dataItem;

		//If the column isn't editable, or if we've already applied 
		//jEditable, don't do anything.
		if (column.editable !== true || !isEditableCallback(column, tdElement, dataItem) || tdElement.data("editable") === true) {
			return;
		}

		//Additional options are stored in the settings, making them available to callback functions.
		var options = $.extend({}, JEditableModule.defaultOptions,
		    { callback: base.afterSave, column: column, tdElement: tdElement, data: base.beforeEdit, name: column.field });

		if (column.type) {
			//If the type isn't supported, log it.
			if (!$.editable.types[column.type]) {
				//Only log the first time
				if (!base.missingEditors[column.type]) {
					console.warn("Unable to find editor for type " + column.type + " in jEditable.");
					base.missingEditors[column.type] = true;
				}
				return;
			}

			options.type = column.type;
		}

		//Special-case: the built-in select editor requires additional properties that define the options.
		if (column.type == "select") {
			options.data = column.selectOptions;
			//This will end edit mode when the user presses enter.
			tdElement.keyup(function(event) { if (event.keyCode == enterKey) $("select", tdElement).blur(); });
		}

		//Make the element editable.
		tdElement.editable(base.saveCell, options)
				.addClass("editable")
		//Mark the cell as editable, that way we won't try to make it editable again in the future.
				.data("editable", true);
	}
	
	//Callback that is run *before* an element is edited.
	base.beforeEdit = function(value, settings) {

		//Post an event and allow callers to modify the value.
		var event = $.Event("cellEditing");
		event.column = settings.column;
		event.currentValue = value;

		base.liteGrid.$el.trigger(event);

		return event.currentValue;
	}

	//Callback that is run whenenever a cell has been saved.  This
	//stores the cell value in the underlying data item.
	base.saveCell = function(value, settings) {

		var cell = $(settings.tdElement);

		//See if the value actually changed
		var dataItem = cell.parent().data("dataItem");

		var currentValue = dataItem[settings.column.field];

		//An event is raised so that interested parties can modify the
		//value prior to attempting to persist it.  
		//TODO: ADD HOOKS FOR VALIDATION!
		var event = $.Event("valueChanged");
		event.currentValue = currentValue;
		event.newValue = value;
		event.column = settings.column;
		event.tdElement = settings.tdElement;

		base.liteGrid.$el.trigger(event);

		//Subscribers may have modified the new value
		value = event.newValue;

		//If the value hasn't changed, or if the value is still null/empty, don't do anything.
		if (currentValue == value || ((currentValue || null) == null && value == "")) {
			settings.valueChanged = false;
		}
		else {
			//Mark the cell as having been changed.  This is used by the 
			//callback handler.
			settings.valueChanged = true;
			cell.addClass("modified");
			cell.addClass("ui-state-highlight");

			//Empty strings are treated as nulls.
			dataItem[settings.column.field] = (value === "") ? null : value;
			cell.parent().data("dataItem", dataItem);
		}

		return value;
	}

	//Callback that is run after a cell's value has been changed. 
	base.afterSave = function(value, settings) {
	if (settings.valueChanged == true) {
	        var event = $.Event("columnBound");
	        event.column = settings.column;
	        event.element = settings.tdElement;

	        base.liteGrid.$el.trigger(event);
		}
	}
}
JEditableModule.defaultOptions = { placeholder: "", onblur: "submit", type: "text" };

//Additional editors supported by the grid.
//TODO: Make this use the currency plug-in?
$.editable.addInputType("currency", {
	element: $.editable.types.text.element
});